Creating dynamic inventory with Unreal Engine, is easy you just need to know where to start so I will help you with some tips
→ Use C++ as calculations can be faster and dynamically changed using integration with blueprints
→ Use singletons and interfaces to store informations globally so can acessed easier
→ Always comment your comments with the necessary informations you may need after you need later to maintain the code working
First off create a new C++ project if you don't already have one, after that import any kind of interface stuff you want to your items for now i will not import anything
I will use the basic borders and images from unreal engine,
Now create a new C++ class of type UUserWidget with the name of _slot, use public (the reason of using the _ before the name is to avoid conflicts with engine default slot names) this will give you access to the user widget class inheritence from the engine defaults. after the code compiles and Visual studio is opened fix some errors that may happen if some sort of weird bug happen. Usually is the include file on the source file that is not with the correct path just fix it
// Your copyright notice
#include "Public/YourFilePath/_slot.h"
Back to the engine create a new C++ class of the type UUserWidget with the name of _grid do the same thing fixing the same issues from the bug, notice that this may or may not happen to you
//Your Copyright Notice
#include "Public/YourFilePath/_grid.h"
With this problem fixed we can procced to the next steps to create our grid slot "inventory" panel
// Your copyright notice
#pragma once
#include "CoreMinimal.h"
#include "Blueprint/UserWidget.h"
#include "_slot.generated.h"
/**
* Grid slot used to added the back panel to the inventory
**/
UCLASS()
class MY_PROJECT_API _slot : public UUserWidget
{
GENERATED_BODY()
public:
// Overriden from UUserWidget
// Initialize all the neccessary slots and information inside the slot as images and borders
virtual bool Initialize() override;
// Works similarly to a Begin play in this ocassion
virtual void NativeConstruct() override;
public:
// background of this slot
UPROPERTY(EditDefaultsOnly,BlueprintReadWrite,Category = "Slot", meta = (BindWidget))
class UImage* _background;
// the icon used by the item when using this slot
UPROPERTY(EditDefaultsOnly,BlueprintReadWrite,Category = "Slot", meta = (BindWidget))
class UImage* _icon;
// The index of this slot
UPROPERTY(EditDefaultsOnly,BlueprintReadWrite,Category = "Slot")
int32 _index;
};
Explaining the above code:
Code imported from the UUserWidget class, this class is the base class if you want to use umg in unreal engine 4 and C++ without touching slates
// Initialize all the neccessary slots and information inside the slot as images and borders
virtual bool Initialize() override;
Initialize overriden function is the function that sort of Initialize all the information of the widget inside the unreal engine, this works inside the engine and here you have to check every pointer and references you get as if you don't you have a high change of code errors and engine crashes. seriously, I've spend a lot of time without noticing that, and return a bool , for the experiences I had need to return true or the engine might crash
// Works similarly to a Begin play in this ocassion
virtual void NativeConstruct() override;
Native Construct override function will allow us to use our items as soon as they are constructed on the viewport of the player, or created does not return nothing as it's a void
// background of this slot
UPROPERTY(EditDefaultsOnly,BlueprintReadWrite,Category = "Slot", meta = (BindWidget))
class UImage* _background;
// the icon used by the item when using this slot
UPROPERTY(EditDefaultsOnly,BlueprintReadWrite,Category = "Slot", meta = (BindWidget))
class UImage* _icon;
// The index of this slot
UPROPERTY(EditDefaultsOnly,BlueprintReadWrite,Category = "Slot")
int32 _index;
UImage* is a base class from the engine, we can use this to create images on the umg(UUserWidget) we are Creating other class we can use is the UBorder* that has similar implementation with a little bit more properties to it, but for now I'm going to use UImage*
// Your copyright notice
#include "Public/YourFilePath/_slot.h"
// Initialize all the neccessary slots and informations inside the slot as images and borders
bool _slot::Initialize()
{
Super::Initialize();
// we need a valid background image and a valid icon image object otherwise this cannont be initialized
if(!_background || !_icon) return false;
// set the color of this background and make the icon transparent/invisible
_background->SetColorAndOpacity(FLinearColor(0.5f,0.5f,0.5f,0.5f));
_icon->SetColorAndOpacity(FLinearColor(0.f,0.f,0.f,0.f));
}
As I'm a lazy bastard I will just copy the hole code here the end code :|
// header file
class _slot; // forward declaration of the slot class
/**
* class that is going to receive all the slots and provided a visual of the inventory
*/
UPROPERTY(EditAnywhere, BlueprintReadWrite,meta = (BindWidget))
class UUniformGridSlot* _inventoryGridPanel;
/**
* Class used to create the inventory slots on the grid
*/
UPROPERTY(EditAnywhere, BlueprintReadWrite)
TSubclassOf<_slot> _inventorySlotClass;
/**
* Array containing all of the inventory slots on the grid panel
*/
UPROPERTY(EditAnywhere, BlueprintReadWrite)
TArray<_slot*> _inventorySlots;
//Source file
/**
* Initialize the grid panel slots
*/
void US_InventoryScreen::_initializeGridPanelSlots()
{
if (!_inventoryGridPanel) return;
if (!_inventorySlotClass) return;
// number of columns you want this grid to have
const int32 Col = 10;
// the number of rows you want the grid to have
const int32 Row = 1;
int32 Rows = 0; // current number of rows
//↓ ¬ Number of items in the inventory
for (int32 a = 0; a <= 60;)
{
US_InventorySlot* InventorySlot = CreateWidget<_slot>(GetOwningPlayer(), _inventorySlotClass);
if (!InventorySlot) return;
_inventorySlots.Add(InventorySlot);
InventorySlot->AddToViewport(999);
InventorySlot->_slotBackground->SetBrushFromTexture(nullptr); // you can set the icon you want the item to have here
InventorySlot->_slotStack->SetVisibility(ESlateVisibility::Hidden); // we hide the slot stack too
UUniformGridSlot* _gridSlot = _inventoryGridPanel->AddChildToUniformGrid(InventorySlot, Rows, (a % Col));
if (!_gridSlot) return;
a++;
_gridSlot->SetHorizontalAlignment(EHorizontalAlignment::HAlign_Fill);
_gridSlot->SetVerticalAlignment(EVerticalAlignment::VAlign_Fill);
if (a % Col == Row - 1)
{
Rows++;
}
}
}